<?php

/*
 *  CI_Report - Generate reports
 *  
 *  Gerador de relatórios 
 *  
 *  @package CodeIgniter
 *  @category Libraries
 *  @author   Carlos O Carvalho
 *  @license  http://www.opensource.org/licenses/MIT
 *  @version  1.2.3
 * 
 */

class CI_Report {

    private $sql;
    var $write; // obj;
    var $columns = array();
    var $group;
    var $total;
    private $results = array();
    private $actions = array();
    private $formats = array();
    private $data_document = array('start' => '', 'end' => '');
    private $data_count_diff = array();
    private $actions_no_permitions = array('display_subtotal', 'count_and_order');
    private $_index = 1;

    function set_writer($write) {
        $this->write = $write;
    }

    function set_sql($sql) {
        $this->sql = $sql;
    }

    function add_column($name, $label, $align = 'L') {
        $this->columns[] = array('name' => $name, 'label' => $label, 'align' => $align);
    }

    function set_group($group) {
        $this->group = $group;
    }
  
     function set_primery_key($key){

        $this->primary_key = $key;
     }
    function set_start_document($data) {
        $this->data_document['start'] = $data;
    }

    function set_end_document($data) {
        $this->data_document['end'] = $data;
    }

    function set_action($field, $action) {
        //$field = isset($this->formats[$field]) ? 'ft-'.$this->_index.'-'.$field : (isset($this->actions[$field]) ? 'ac-'.$this->_index.'-'.$field : $field);
        if (preg_match('#format#', $action)):
            $field = 'ft-' . $this->_index . ':' . $field;
            $this->formats[$field] = $action;
        else:
            $field = 'ac-' . $this->_index . ':' . $field;
            $this->actions[$field] = $action;
        endif;
        $this->_index +=1;
    }

    
    function generate($type = 'normal', $header_by_group = true) {


        if (!isset($this->write)) {
            throw new Exception('Nenhum escritor foi definido ');
        }

        if (!isset($this->sql)) {
            throw new Exception('Nenhuma sql foi definida ');
        }


        $write = $this->write;

        if ($type == 'normal') {
            $my_w = $write->widths;
            array_unshift($my_w, 11);
            $this->write->widths = $my_w;
        }

        if (!$this->group && $type == 'normal') {

            $this->add_header_columns();
        }
        $ci = &get_instance();
        //echo $this->sql;
        //exit;


        $qr = $ci->db->query($this->sql);



        if (!empty($this->data_document['start'])) {
            $this->write->add_header($this->data_document['start']);
        }
        $matriz = array('line' => array(), 'columns' => array(), 'widths' => array(), 'titles' => array(), 'columns_name' => array());
        $data_result = $qr->result();



        $this->groups_list = array();
        $this->group_by_subtotais = false;
        $this->group_by_subtotais_display = false;
        foreach ($this->group as $group) {
            if (!empty($group)) {
                $this->groups_list[$group] = '';
            }
        }

        foreach ($this->columns as $column) {
            $this->apply_action($column['name'], '', false);
            if ($this->now_action != false && $this->now_action == 'display_subtotal') {

                $this->group_by_subtotais[] = $column['name'];
            }
        }

        $num_itens_group = count($this->groups_list);

        if ($this->group_by_subtotais !== false) {
            foreach ($data_result as $row):
                foreach ($this->group_by_subtotais as $group) {
                    $this->group_by_subtotais_display[] = $row->$group;
                }
            endforeach;

            $this->group_subtotais_list = array_values(array_unique($this->group_by_subtotais_display));
            //reset
            $this->group_by_subtotais_display = array();

            foreach ($this->group_subtotais_list as $gpby) {
                $this->group_by_subtotais_display['subtotais_group'][$gpby] = array();
            }
        }
        $gp = false;
        $html = array();
        $clr = false;
        $count_group = 0;
        if (count($data_result) == 0) {
            return false;
        }
        $ic = 1;
        $primary_key = $this->primary_key;
        $_index = 1;
        $pages_loaded = array();
        $str_loaded  = array();
        
        $key_now = 0;
        $last_page = 1;

        foreach ($data_result as $cikey=>$row):
            $this->_row = $row;


            //generate normal report
            if ($type == 'normal') {
                if ($num_itens_group > 0) {
                    if ($header_by_group) {
                        $this->add_header_columns();
                    }
                    foreach ($this->groups_list as $group => $group_value) {
                        $group_style = $gp ? 'group' : 'groupi';
                        if ($group_value !== $row->$group) {
                            $write->add_row();
                            $group_value_cell = str_replace(array('_', '-'), array(' ', ' '), strtoupper($row->$group));
                            $this->apply_action($group, $row->$group);

                            $group_value_cell = $this->apply_format($group, $group_value_cell,$row->$primary_key);
                            $write->add_cell($ic, 'left', $group_style);
                            $write->add_cell($group_value_cell, 'left', $group_style, count($this->columns) - 1);
                        }

                        $this->groups_list[$group] = $row->$group;

                        $ic+=1;
                        $gp = !$gp;
                    }
                    //reset line 
                    $clr = false;
                }else{

                ///add
                    if($write->get_page() == 1 && !in_array($write->get_page(), $pages_loaded)){
                         $this->add_header_columns();
                         $pages_loaded[]=$write->get_page();

                    }
                    if(!in_array($write->get_page(), $pages_loaded)){

                         $this->add_header_columns();
                         $pages_loaded[]=$write->get_page();
                    }


                }

                $style = $clr ? 'dataeven' : 'dataodd';
                $write->add_row();
                foreach ($this->columns as $column):
                    $field = $column['name'];
                    $align = $column['align'];
                    $value = isset($this->groups_list[$field]) ? null : isset($row->$field) ? $row->$field : null;
                    if (!is_null($value)) {
                        $this->apply_action($field, $row->$field);
                        $ivalue = $this->apply_format($field, $row->$field, $row->$primary_key);
                        $write->add_cell(utf8_decode($ivalue), $align, $style);
                    } else {
                         $str = ' ';
                         if(!isset($keys_loaded[$row->$primary_key])){
                            $keys_loaded[$row->$primary_key] = true;
                            $str = $_index;
                            $_index+=1;

                         }
                          $write->add_cell($str, $align, $style);
                       
                    }

                endforeach;
            }

            if ($type == 'matriz') {

                foreach ($this->columns as $line => $column) {
                    $field = $column['name'];

                    if ($line == 0 && !in_array($row->$field, $matriz['line'])) {
                        $matriz['line'][] = $row->$field;
                    }
                    if ($line == 1 && !in_array($row->$field, $matriz['columns'])) {
                        $matriz['columns'][] = $row->$field;
                        $matriz['widths'][] = $write->widths['1'];
                        $matriz['columns_name'][] = $field;
                        // if (!in_array($field, $matriz['titles'])) {
                        $matriz['titles'][] = $column['label'];
                        // }
                    }
                    // $matriz_col = $this->columns;
                    //$matriz['data'][]
                }
            }


         $clr = !$clr;
            
        endforeach;
        
        
        if ($type == 'matriz') {
            $border = 1;
            $totals = array();
            $last_totals = 0;
            sort($matriz['columns']);
            sort($matriz['line']);
            $write->add_row();
            array_unshift($matriz['widths'], $write->widths['0']);
            $matriz['widths'][] = 40;
            $write->widths = $matriz['widths'];
            $write->add_cell($this->columns['0']['label'], 'L', 'title');
            foreach ($matriz['columns'] as $k => $column) {

                $cnt = is_numeric($column) ? $matriz['titles'][$k] . ' ' . $column : $matriz['titles'][$k];
                $write->add_cell($cnt, 'L', 'title');
            }
            $write->add_cell('Total(s) ', 'R', 'title');



            foreach ($matriz['line'] as $row) {
                $row_name = $this->columns['0']['name'];
                $style = $clr ? 'dataeven' : 'dataodd';
                $write->add_row();
                $write->add_cell(utf8_decode($row), 'L', $style);
                $row_total = 0;
                foreach ($matriz['columns'] as $ikey => $column) {
                    $cnt = 0;
                    $ifield = $matriz['columns_name'][$ikey];
                    foreach ($data_result as $line) {
                        if ($line->$ifield == $column && $line->$row_name == $row) {
                            $cnt +=1;
                        }
                        //count columns
                    }
                    $write->add_cell($cnt, 'L', $style);
                    $row_total = $row_total + $cnt;
                    if (!isset($totals[$column])) {
                        $totals[$column] = 0;
                    }
                    $totals[$column] = $totals[$column] + $cnt;
                }
                $write->add_cell($row_total, 'R', $style);
                $last_totals = $last_totals + $row_total;
                $clr = !$clr;
            }
            //array_unshift($matriz['widths'], $write->widths['0']);
            //$matriz['widths'][] = 40;
            //$write->widths = $matriz['widths'];
            $write->add_row();
            $write->add_cell('', 'L', 'final');
            foreach ($totals as $total) {
                $write->add_cell($total, 'L', 'final');
            }
            $write->add_cell($last_totals, 'R', 'final');
        } else {
            $this->write->add_row();
            $this->print_sub_totais();
            $this->print_totais();
    
            $this->write->add_row();
        }
        
        $this->write->apply_style('end_doc');
        if (!empty($this->data_document['end'])) {
            $this->write->add_header(str_replace('&nbsp;', ' ', $this->data_document['end']));
        }
        return true;
    }

    private function print_totais() {
        $actions_totais = array();

        $primary_key = $this->primary_key;
        if (isset($this->results['actions'])):
            $num_columns = count($this->columns) - 1;
            foreach ($this->results['actions'] as $col => $result):
                foreach ($this->columns as $i => $column):
                    if ($i == 0):
                        $border = 'LTB';
                    endif;
                    if ($i > 0 && $i < ($num_columns)):
                        $border = 'TB';
                    endif;
                    if ($i == $num_columns):
                        $border = 'RTB';
                    endif;
                    $name = $column['name'];
                    if ($col == $name):
                        foreach ($result as $idata):
                            $tvalue = $this->apply_format($name, $idata,$col);
                            $actions_totais[$name] = $tvalue;
//                            if (isset($this->formats[$name])) {
//                                call_user_func_array(array($this, $this->formats[$name]), array($name, &$idata));
//                                $idata = utf8_decode($this->results['format'][$name]);
//                                $actions_totais[$name] = $idata;
//                            } else {
//                                $actions_totais[$name] = $idata;
//                            }

                        endforeach;
                    endif;
                endforeach;
            endforeach;
            //line label totais
            $this->write->add_row();
            $this->write->add_cell(' ', 'L', 'dataodd', $num_columns + 1, false);
            $this->write->add_row();
            $this->write->add_cell(' ', 'L', 'dataodd', $num_columns + 1, 'B');
            $this->write->add_row();
            $this->write->add_cell('Total(s)', 'L', 'final', $num_columns + 1, 'LR');

            $this->add_header_columns();
            //line view totais
            $this->write->add_row();
            foreach ($this->columns as $key => $column) {
                if ($key == 0):
                    $border = 'LTB';
                endif;
                if ($key > 0 && $key < ($num_columns)):
                    $border = 'TB';
                endif;
                if ($key == $num_columns):
                    $border = 'RTB';
                endif;
                $data = isset($actions_totais[$column['name']]) ? $actions_totais[$column['name']] : '';
                $this->write->add_cell($data, $column['align'], 'final', 1, $border);
            }
        endif;
    }

    private function print_sub_totais($final = true) {
        $actions_totais = array('titles' => array());
        //if ($this->num_subtotais == 1 && $fi) {
        //echo '<pre>';
        //print_r($this->results['actions']['subtotais_group']);
        //exit;
        if (isset($this->results['actions']['subtotais_group'])):
            $num_columns = count($this->columns) - 1;
            $this->write->add_row();
            $this->write->add_cell('SubTotal(s)', 'L', 'groupi', $num_columns + 1, 'TLR');
            foreach ($this->results['actions']['subtotais_group'] as $colgroup => $result):

                if (is_array($result)) {
                    $actions_totais['titles'][] = $colgroup;
                    foreach ($result as $col => $colvalue) {
                        $ivalue = '';
                        foreach ($this->columns as $i => $column) {
                            if ($i == 0):
                                $border = 'LTB';
                            endif;
                            if ($i > 0 && $i < ($num_columns)):
                                $border = 'TB';
                            endif;
                            if ($i == $num_columns):
                                $border = 'RTB';
                            endif;
                            $name = $column['name'];
                            if ($col == $name):
                                foreach ($colvalue as $val) {
                                    $ivalue = $this->apply_format($name, $val,$col);
                                    $actions_totais[$colgroup][$name] = $ivalue;
                                }


                            endif;
                        }
                    }
                }

            endforeach;
            //line label totais
            //$this->write->add_cell('SubTotal(s)', 'L', 'final', $num_columns + 1, 'LR');
            //line view totais

            foreach ($actions_totais['titles'] as $row) {

                $this->write->add_row();
                $this->write->add_cell((!empty($row) || $row == '' ? $row : 'Outro(s)'), 'L', 'groupi', $num_columns + 1);
                $this->add_header_columns();
                $this->write->add_row();
                foreach ($this->columns as $key => $column) {
                    if ($key == 0):
                        $border = 'LTB';
                    endif;
                    if ($key > 0 && $key < ($num_columns)):
                        $border = 'TB';
                    endif;
                    if ($key == $num_columns):
                        $border = 'RTB';
                    endif;
                    $data = isset($actions_totais[$row][$column['name']]) ? $actions_totais[$row][$column['name']] : '';
                    $this->write->add_cell($data, $column['align'], 'groupsubtotal', 1, $border);
                }
            }
        endif;
//        if (!$final) {
//            $this->add_header_columns();
//            $this->write->add_row();
//        }
//        //}
        $this->results['actions']['subtotais_group'] = array();
    }

    function add_header_columns() {
        if (count($this->columns) == 0) {
            throw new Exception('Nenhuma coluna foi definida ');
        }



        $this->write->add_row();
        foreach ($this->columns as $col):
            $this->write->add_cell($col['label'], $col['align'], 'title');
        endforeach;
    }

    function sum($field, $value) {
        if (!isset($this->results['actions'][$field]['sum'])) {
            $this->results['actions'][$field]['sum'] = 0;
        }
        $this->results['actions'][$field]['sum'] += $value;

        if ($this->group_by_subtotais_display !== false) {
            $row = $this->_row;
            $group_subtotal = false;
            $column = false;
            foreach ($this->group_by_subtotais as $group_by) {
                $group_subtotal = $row->$group_by;
                $column = $group_by;
            }
            if ($group_subtotal !== false) {
                if (!isset($this->results['actions']['subtotais_group'][$group_subtotal][$field]['sum'])) {
                    $this->results['actions']['subtotais_group'][$group_subtotal][':column:'] = $column;
                    $this->results['actions']['subtotais_group'][$group_subtotal][$field]['sum'] = 0;
                }
                $this->results['actions']['subtotais_group'][$group_subtotal][$field]['sum'] += $value;
            }
            //echo '<pre>';
            //print_r($this->results['actions']['subtotais_group'][$this->display_group_by]);
        }
    }


    private function apply_action($field, $value, $apply = true) {
        $this->now_action = false;
        foreach ($this->actions as $db_field => $fn) {
            if (strpos($db_field, $field)) {
                if (method_exists($this, $fn)) {
                    $this->now_action = $fn;
                    if ($apply) {
                        call_user_func_array(array($this, $fn), array($field, $value));
                    }
                }
            }
        }
    }

    private function apply_format($field, $value, $key ,$apply = true) {
        $call_result = $value;
        foreach ($this->formats as $db_field => $fn) {
            if (strpos($db_field, $field)) {
                if (method_exists($this, $fn)) {
                     $call_result = call_user_func(array($this, $fn), $field, $call_result,$key);
                    // return $this->results['format'][$field];
                }
            }
        }
        return $call_result;
    }


    function count($field) {
        //definindo os indices
        if (!isset($this->results['actions'][$field]['count'])) {
            $this->results['actions'][$field]['count'] = 0;
        }
        $this->results['actions'][$field]['count'] += 1;
        //no agrupado
        if ($this->group_by_subtotais_display != false) {
            $row = $this->_row;
            $group_subtotal = false;
            $column = false;
            foreach ($this->group_by_subtotais as $group_by) {
                $group_subtotal = $row->$group_by;
                $column = $group_by;
            }
            if ($group_subtotal !== false) {
                if (!isset($this->results['actions']['subtotais_group'][$group_subtotal][$field]['count'])) {
                    $this->results['actions']['subtotais_group'][$group_subtotal][':column:'] = $column;
                    $this->results['actions']['subtotais_group'][$group_subtotal][$field]['count'] = 0;
                }
                $this->results['actions']['subtotais_group'][$group_subtotal][$field]['count'] += 1;
            }
        }
    }

    function display_subtotal($field, $value) {
//        $value = trim($value);
//        $this->display_group_by = !empty($value) ? $value : 'Outro(s)';
//        $this->display_group_by_field = $field;
    }

    function count_diff($field, $value) {
        if (!isset($this->results['actions'][$field]['count_diff'])) {
            if (!isset($this->data_count_diff[$field])) {
                $this->data_count_diff[$field] = array();
            }
            if (!in_array($value, $this->data_count_diff[$field])) {
                $this->results['actions'][$field]['count_diff'] = 1;
                $this->data_count_diff[$field][] = $value;
            }
        }



        if (!in_array($value, $this->data_count_diff[$field])) {
            $this->results['actions'][$field]['count_diff'] += 1;
            $this->data_count_diff[$field][] = $value;
        }


        if ($this->group_by_subtotais_display !== false) {
            $row = $this->_row;
            $group_subtotal = false;
            $column = false;
            foreach ($this->group_by_subtotais as $group_by) {
                $group_subtotal = $row->$group_by;
                $column = $group_by;
            }
            if ($group_subtotal != false) {
                if (!isset($this->results['actions']['subtotais_group'][$group_subtotal][$field]['count_diff'])) {
                    $this->results['actions']['subtotais_group'][$group_subtotal][':column:'] = $column;
                    $this->results['actions']['subtotais_group'][$group_subtotal][$field]['count_diff'] = 0;
                }
                //$this->data_count_diff
                if (!isset($this->data_count_diff['subtotais_group'][$group_subtotal][$field])) {
                    if (!isset($this->data_count_diff['subtotais_group'][$group_subtotal][$field])) {
                        $this->data_count_diff['subtotais_group'][$group_subtotal][$field] = array();
                    }

                    if (!in_array($value, $this->data_count_diff['subtotais_group'][$group_subtotal][$field])) {
                        $this->results['actions']['subtotais_group'][$group_subtotal][$field]['count_diff'] = 1;
                        $this->data_count_diff['subtotais_group'][$group_subtotal][$field][] = $value;
                    }
                }
                if (!in_array($value, $this->data_count_diff['subtotais_group'][$group_subtotal][$field])) {
                    $this->results['actions']['subtotais_group'][$group_subtotal][$field]['count_diff'] += 1;
                    $this->data_count_diff['subtotais_group'][$group_subtotal][$field][] = $value;
                }
            }
            //echo '<pre>';
            //print_r($this->results['actions']['subtotais_group'][$this->display_group_by]);
        }
    }

    function count_empty($field, $value) {
        if (!isset($this->results['actions'][$field]['count_empty'])) {
            $this->results['actions'][$field]['count_empty'] = 0;
        }
        if (empty($value) OR is_null($value)) {
            $this->results['actions'][$field]['count_empty'] += 1;
        }
    }

    function media($value, $field) {
        if (isset($this->results[$field])) {
            $iv = $this->results[$field]['media']['value'] + $value;
            $i = $this->results[$field]['media']['count_data'] + 1;
            $this->results[$field]['media'] = array('value' => $iv, 'count_data' => $i);
        } else {
            $this->results[$field]['media'] = array('value' => $value, 'count_data' => 1);
        }
    }

    function format_moeda($field, $value) {
        return 'R$ ' . number_format($value, 2, ',', '.');
        //return $this;
    }

    function format_data($field, $value) {
          return date('d/m/Y',strtotime($value));
        // return format_data_br($value);
        
    }

    function save($name) {
        $this->write->save_file($name);
        return true;
    }

    function show($name = '') {
        $this->write->show_file($name);
    }

    function download($name = '') {
        $this->write->download_file($name);
    }

    function results_callbacks() {
        return (object) $this->results;
    }

    public function format_no_repeat($field,$value,$id){
                   
                   if(!isset($this->presents[$id][$field])){
                           $this->presents[$id][$field]=array();
                   }


                   if(!in_array($value,$this->presents[$id][$field])){
                         $this->presents[$id][$field][] = $value;
                         return $value;
                   }

                   return '    ';

 
    }






   public static function optionsReport(){

               $options = array(
                  'action_num'=>'Somar',
                   'action_media' => 'Média'
                                           );  

   } 

}